package com.powernode.strategy.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.powernode.config.WxParamConfig;
import com.powernode.constant.AuthConstants;
import com.powernode.domain.LoginMember;
import com.powernode.mapper.LoginMemberMapper;
import com.powernode.model.SecurityUser;
import com.powernode.strategy.LoginStrategy;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashSet;

/**
 * @create: 2024/7/16
 * @author: gyhe10
 * @description: 商城购物系统登录策略实现类
 **/

@Service(AuthConstants.MEMBER_LOGIN)
public class MemberLoginStrategy implements LoginStrategy {

    @Resource
    private WxParamConfig wxParamConfig;
    @Resource
    private LoginMemberMapper loginMemberMapper;

    /**
     * 会员购物系统登录方法
     * @param username 微信小程序登录凭证code
     * @return
     */
    @Override
    public UserDetails realLogin(String username) {

        // 携带参数（appid、appsecret、code）调用微信接口服务器中的 登录凭证校验接口
        // String url = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
        // 获取登录凭证校验接口URL
        String url = String.format(wxParamConfig.getUrl(), wxParamConfig.getAppid(), wxParamConfig.getSecret(), username);

        // 使用GET方法调用接口
        String jsonStr = HttpUtil.get(url);

        // 微信小程序登录凭证校验接口返回的json数据示例
        /*{
            "openid":"xxxxxx",
            "session_key":"xxxxx",
            "unionid":"xxxxx",
            "errcode":0,
            "errmsg":"xxxxx"
        }*/
        // 判断响应结果是否有值
        if (!StringUtils.hasText(jsonStr)) {
            throw new InternalAuthenticationServiceException("登录异常，请重试");
        }

        // 使用fastjson将微信小程序登录凭证校验接口返回json字符串转为json对象
        JSONObject jsonObject = JSON.parseObject(jsonStr);

        // 获取openId
        String openId = jsonObject.getString("openid");

        // 判断openId是否为空
        if (!StringUtils.hasText(openId)) {
            throw new InternalAuthenticationServiceException("登录异常，请重试");
        }

        // 根据openId从数据库member表查询会员信息，如果会员信息不存在，证明是新会员，保存会员信息到数据库member表
        LoginMember loginMember = loginMemberMapper.selectOne(new LambdaQueryWrapper<LoginMember>()
                .eq(LoginMember::getOpenId, openId));

        // 如果会员信息不存在，则保存会员信息到数据库member表
        if (ObjectUtil.isNull(loginMember)) {
            loginMember = registerMember2Db(openId);
        }

        // 会员存在，判断会员账号状态
        if (1 != loginMember.getStatus()) {
            throw new InternalAuthenticationServiceException("账号状态异常，请联系管理员");
        }

        // 会员存在且状态正常，返回SpringSecurity框架的UserDetails对象，也就是SecurityUser对象
        SecurityUser securityUser = new SecurityUser();
        securityUser.setUserId(Long.valueOf(loginMember.getId()));
        securityUser.setLoginType(AuthConstants.MEMBER_LOGIN);
        securityUser.setUsername(openId);
        securityUser.setStatus(loginMember.getStatus());
        // SpringSecurity框架的UserDetails对象必须要有密码，而且密码必须加密处理
        securityUser.setPassword(wxParamConfig.getPwd());
        securityUser.setOpenId(openId);

        // SecurityUser对象剩余两个属性如果设置为null会导致报空指针
        securityUser.setShopId(1L);
        HashSet<String> objects = new HashSet<>();
        objects.add("");
        securityUser.setPerms(objects);

        return securityUser;
    }

    private LoginMember registerMember2Db(String openId) {
        // 获取请求的IP
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String ip = request.getRemoteAddr();

        LoginMember loginMember = new LoginMember();
        loginMember.setOpenId(openId);
        loginMember.setStatus(1);
        loginMember.setCreateTime(new Date());
        loginMember.setUpdateTime(new Date());
        loginMember.setUserLasttime(new Date());
        loginMember.setUserRegip(ip);
        loginMember.setUserLastip(ip);
        loginMember.setScore(0);

        // 保存会员信息到数据库member表
        loginMemberMapper.insert(loginMember);

        return loginMember;
    }

    /*public static void main(String[] args) {
        System.out.println(new BCryptPasswordEncoder().encode("WECHAT"));
    }*/
}
